﻿#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>


//int main()
//{
//	int a[] = { 1,2,3,4 };
//	printf("%d\n", sizeof(a));//16
//	//对应前面的第一点，数组名在sizeof内部代表的是整个数组，计算的是整个数组的大小。
//	//而这里在定义数组时并没有给定大小，但是a内部存放了4个元素，所以整个大小就是4×4=16个字节。
//	printf("%d\n", sizeof(a + 0));//4/8
//	//这里a并没有放到sizeof内部，所以a代表数组首元素的地址，首元素地址+1，还是首元素的地址
//	// 不要在这里跟我犟嘴说a+0不就是a吗，请注意：结果是由语法制作的人来规定的，都是龟腚，就不要犟嘴辣
//	//指针（地址）在32位平台上是4个字节大小，在64位平台上是8个字节大小
//	printf("%d\n", sizeof(*a));//4
//	//首元素的地址解引用后就是a[0]，这里a[0]的类型是int，所以大小是4
//	printf("%d\n", sizeof(a + 1));//4/8
//	//首元素地址+1，得到第二个元素的地址，地址的大小就是4/8个字节
//	printf("%d\n", sizeof(a[1]));//4
//	//a[1]的类型是int，大小为4
//	printf("%d\n", sizeof(&a));//4/8
//	//&a，取出的是整个数组的地址，地址的大小就是4/8
//	printf("%d\n", sizeof(*&a));//16
//	//两种解释：
//	//第一种：*和&可以相互抵消，那么这里就可以写成sizeof(a)，那么结果就和第一个一样，就是16
//	//第二种：&a取出整个数组的地址，解引用后就变回去跟原来的数组名a等效了。那么结果就是16
//	printf("%d\n", sizeof(&a + 1));//4/8
//	//还是个地址，只不过是整个数组后面的地址，那么地址的大小就是4/8，如果不明白请看下面的图解。
//	printf("%d\n", sizeof(&a[0]));//4/8
//	//首元素的地址，结果就是4/8
//	printf("%d\n", sizeof(&a[0] + 1));//4/8
//	//首元素的地址+1，得到第二个元素的地址，地址大小就是4/8
//	return 0;
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%d\n", sizeof(arr));//6
//	//这里数组内放了6个元素，每个元素类型为char，故总大小为6
//	printf("%d\n", sizeof(arr + 0));//4/8
//	//跟前面的一样，地址大小就是4/8
//	printf("%d\n", sizeof(*arr));//1
//	//首元素的地址解引用后为a[0]，类型为char，大小为1
//	printf("%d\n", sizeof(arr[1]));//1
//	//a[1]，类型为char，大小为1
//	printf("%d\n", sizeof(&arr));//4/8
//	//整个数组的地址，地址大小为4/8
//	printf("%d\n", sizeof(&arr + 1));//4/8
//	//整个数组后面的地址，还是地址，大小为4/8
//	printf("%d\n", sizeof(&arr[0] + 1));//4/8
//	//第二个元素的地址，4/8
//
//	printf("%d\n", strlen(arr));//未知数x
//	//strlen函数统计的是字符串长度，统计时碰到'\0'才停止，但是该数组并没有存放'\0'，所以结果是未知数
//	printf("%d\n", strlen(arr + 0));//未知数x
//	//跟上面一样
//	printf("%d\n", strlen(*arr));//非法访问
//	//strlen函数传参传的是地址，这里将字符'a'传过去了
//	//但是字符'a'有对应的ASCII的值97，所以传过去的地址就是0x00000061(这是十六进制的)
//	//此时访问了这个地址就会造成非法访问
//	printf("%d\n", strlen(arr[1]));//非法访问
//	//跟上面一样，非法访问了地址0x00000062
//	printf("%d\n", strlen(&arr));//未知数x
//	//这里传的是整个数组的地址，但是还是从数组的第一个元素开始的
//	//所以这里的未知数和前两个相同，都是x
//	printf("%d\n", strlen(&arr + 1));//未知数x-6
//	//这里&arr+1，跳过了整个数组，整个数组中有6个元素，所以跟上面的未知数相差了6
//	printf("%d\n", strlen(&arr[0] + 1));//未知数x-1
//	//这里的地址从第二个元素开始，所以跟前面的未知数相差了1
//	return 0;
//}

//int main()
//{
//	//这里和上面的都很类似我就不讲那么细了，一些有区别的细🔒一下就行
//	char arr[] = "abcdef";
//	printf("%d\n", sizeof(arr));//7
//	//字符串中会默认添加一个'\0'，所以表面上看大小为6，实际上是7
//	printf("%d\n", sizeof(arr + 0));//4/8
//	printf("%d\n", sizeof(*arr));//1
//	printf("%d\n", sizeof(arr[1]));//1
//	printf("%d\n", sizeof(&arr));//4/8
//	printf("%d\n", sizeof(&arr + 1));//4/8
//	printf("%d\n", sizeof(&arr[0] + 1));//4/8
//
//	printf("%d\n", strlen(arr));//6
//	//这里因为字符串中有'\0'所以就不是未知数了
//	printf("%d\n", strlen(arr + 0));//6
//	printf("%d\n", strlen(*arr));//非法访问
//	printf("%d\n", strlen(arr[1]));//非法访问
//	printf("%d\n", strlen(&arr));//6
//	printf("%d\n", strlen(&arr + 1));//未知数
//	printf("%d\n", strlen(&arr[0] + 1));//5
//	return 0;
//}

//int main()
//{
//	char* p = "abcdef";
//	//这里的p指向的是字符串中首元素的地址，并且该字符串是一个常量字符串
//	printf("%d\n", sizeof(p));//4/8
//	//这里的p可不是数组，而是字符指针，指针的大小就是4/8
//	printf("%d\n", sizeof(p + 1));//4/8
//	//和上面一样
//	printf("%d\n", sizeof(*p));//1
//	//字符指针解引用变为char，大小为1
//	printf("%d\n", sizeof(p[0]));//1
//	//这里的p[0]就相当于*(p+0),解引用后为类型为char，结果就是1
//	printf("%d\n", sizeof(&p));//4/8
//	//这里是指针的指针，还是指针，结果就是4/8
//	printf("%d\n", sizeof(&p + 1));//4/8
//	//指针的指针+1，还是指针，结果是4/8
//	printf("%d\n", sizeof(&p[0] + 1));//4/8
//	//字符型的地址+1，还是地址，结果是4/8
//
//	printf("%d\n", strlen(p));//6
//	//这里strlen传参传的是首元素的地址，并且字符串中有'\0'，故结果为6
//	printf("%d\n", strlen(p + 1));//5
//	//首元素地址+1，指向了第二个元素的地址，结果为5
//	//printf("%d\n", strlen(*p));//非法访问
//	//printf("%d\n", strlen(p[0]));//非法访问
//	printf("%d\n", strlen(&p));//未知数x
//	printf("%d\n", strlen(&p + 1));//未知数y
//	//上面两个未知数是没有关联的，因为你不知道&p中到底有没有'\0'
//	printf("%d\n", strlen(&p[0] + 1));//5
//	//指向第二个元素的地址
//	return 0;
//}

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48
	//该二维数组中有3×4共12个元素，每个元素的类型为int，故总大小为3×4×4=48
	printf("%d\n", sizeof(a[0][0]));//4
	//第0行第0列的元素大小为4
	printf("%d\n", sizeof(a[0]));//16
	//a[0]代表的是第0行数组的数组名，数组名在sizeof内部表示的是整个数组
	//而这里的整个数组是第0行的数组，所以大小是16
	//a[0]的类型是int*
	printf("%d\n", sizeof(a[0] + 1));//4/8
	//整型指针+1，跳过了一个整型，这里等价于&a[0][1],是个地址，所以结果就是4/8
	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//a[0]+1等价于&a[0][1],再解引用，就是a[0][1],类型为int，结果是4
	printf("%d\n", sizeof(a + 1));//4/8
	//a是二维数组的数组名，数组名代表首元素的地址，二维数组的首元素是第0行整整一行
	//这里就是第0行数组的地址+1，就跳到了1行数组的地址，等价于&a[1],地址的大小为4/8
	printf("%d\n", sizeof(*(a + 1)));//16
	//a+1等价于&a[1]，再解引用就是a[1]
	//a[1]就是第1行数组的数组名，数组名放在sizeof内部，代表整个数组，大小为16
	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//第0行的地址+1，跳到了第1行的地址，等价于&a[1]，地址大小为4/8
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//&a[0]+1等价于&a[1],再解引用就是a[1],a[1]为第1行数组的数组名，在sizeof内部，大小为16
	printf("%d\n", sizeof(*a));//16
	//a代表第一行的地址，也就是&a[0],解引用就是a[0],表示第一行数组的数组名，在sizeof内部，大小为16
	printf("%d\n", sizeof(a[3]));//16
	//第3行数组的数组名，在sizeof内部，大小为16。
	//这里并不会越界访问，因为sizeof内部的是不进行实际操作的。
	return 0;
}